package jarLoadTest;

import org.junit.Test;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class LoadJarAndExe {

    @Test
    public  void exeWithScan() {

        URL[] urls = new URL[] {};
        try {
            MyClassLoader classLoader = new MyClassLoader(urls, null);
            //classLoader.addJar(new File("./lib/jartest-1.0-SNAPSHOT.jar").toURI().toURL());
            //此jar包里带有该项目下没有的依赖，测试证明可以加载
            classLoader.addJar(new File("./lib/jartest-1.0-SNAPSHOT-jar-with-dependencies.jar").toURI().toURL());
            searchClass(classLoader);
            Class<?> clazz = classLoader.loadClass("jarTest.MyJarClassA");
            Object o = clazz.newInstance();
            Method method = clazz.getDeclaredMethod("methodA");
            method.invoke(o);
            classLoader.close();
            //不同的classloader对象可以从不同的Jar包中加载相同名称的class，class在对应加载的classloader下是唯一的
/*
            MyClassLoader classLoader2 = new MyClassLoader(urls, null);
            classLoader2.addJar(new File("E:\\ideaWorkSpace\\jartest\\target\\jartest-1.0-SNAPSHOT.jar").toURI().toURL());
            searchClass(classLoader2);
            Class<?> clazz2 = classLoader2.loadClass("jarTest.MyJarClassA");
            Object o2 = clazz2.newInstance();
            Method method2 = clazz2.getDeclaredMethod("methodA");
            method2.invoke(o2);
            classLoader.close();
            System.out.println(clazz == clazz2);*/

        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    public void searchClass(MyClassLoader classLoader) throws IOException, ClassNotFoundException {
        String basePack = "jarTest";
        //通过当前线程得到类加载器从而得到URL的枚举
        //Enumeration<URL> urlEnumeration = classLoader.getResources(basePack.replace(".", "/"));
        Enumeration<URL> urlEnumeration = classLoader.getResources(basePack);
        while (urlEnumeration.hasMoreElements()) {
            URL url = urlEnumeration.nextElement();//得到的结果大概是：jar:file:/C:/Users/ibm/.m2/repository/junit/junit/4.12/junit-4.12.jar!/org/junit
            String protocol = url.getProtocol();//大概是jar
            if ("jar".equalsIgnoreCase(protocol)) {
                if(!url.toString().contains("jartest-1.0-SNAPSHOT")){
                   continue;
                }
                //转换为JarURLConnection
                JarURLConnection connection = (JarURLConnection) url.openConnection();
                if (connection != null) {
                    JarFile jarFile = connection.getJarFile();
                    if (jarFile != null) {
                        //得到该jar文件下面的类实体
                        Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries();
                        while (jarEntryEnumeration.hasMoreElements()) {
                            /*entry的结果大概是这样：
                                    org/
                                    org/junit/
                                    org/junit/rules/
                                    org/junit/runners/*/
                            JarEntry entry = jarEntryEnumeration.nextElement();
                            String jarEntryName = entry.getName();
                            //这里我们需要过滤不是class文件和不在basePack包名下的类
                            if (jarEntryName.contains(".class") && jarEntryName.replaceAll("/",".").startsWith(basePack)) {
                                String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replace("/", ".");
                                Class cls = classLoader.loadClass(className);
                                System.out.println(cls);
                            }
                        }
                    }
                }
            }
        }
    }




    @Test
    public  void exeWithName() {

        URL[] urls = new URL[] {};
        MyClassLoader classLoader = new MyClassLoader(urls, null);

        try {
            classLoader.addJar(new File("F:\\github\\myJavaTest\\myTest-0.0.1-SNAPSHOT.jar").toURI().toURL());
            Class<?> clazz = classLoader.loadClass("jarLoadTest.MyJarClass");
            Object o = clazz.newInstance();
            Method method = clazz.getDeclaredMethod("methodA");
            method.invoke(o);
            classLoader.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    static class MyClassLoader extends URLClassLoader {

        public MyClassLoader(URL[] urls) {
            super(urls);
        }

        public MyClassLoader(URL[] urls, ClassLoader parent) {
            super(urls, parent);
        }

        public void addJar(URL url) {
            this.addURL(url);
        }

    }
}
